package com.sky.java_nio;

import java.io.RandomAccessFile;
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;

import org.junit.Test;

import com.sun.nio.sctp.SctpServerChannel;

import sun.nio.ch.sctp.SctpServerChannelImpl;

/**
 * 
 *@Description: http://ifeve.com/selectors/
 *@Author:hjt 
 *@Version:1.0.0
 */
public class NIO_Selector {

	/**
	 * 1. Selector（选择器）是Java NIO中能够检测一到多个NIO通道，
	 * 并能够知晓通道是否为诸如读写事件做好准备的组件。
	 * 这样，一个单独的线程可以管理多个channel，从而管理多个网络连接
	 * 
	 * 2.仅用单个线程来处理多个Channels的好处是，只需要更少的线程来处理通道
	 * 
	 * 
	 */
	
	@Test
	public void testSelector() throws Exception {
		RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
		FileChannel      fromChannel = fromFile.getChannel();
		
		SctpServerChannel channel = SctpServerChannelImpl.open();
		
		//通过调用Selector.open()方法创建一个Selector
		Selector selector = Selector.open();
		
		//为了将Channel和Selector配合使用，必须将channel注册到selector上
		channel.configureBlocking(false);
		SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
		//注意：注册的channel必须是非阻塞的，FileChannel不能切换到非阻塞模式，套接字通道都可以
		//注册第二个参数表示监听的事件，有：Connect（OP_CONNECT）、Accept（OP_ACCEPT）、Read（OP_READ）、Write（OP_WRITE）
		
//		监听多个事件
		int interestSet_1 = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

		//当向Selector注册Channel时，register()方法会返回一个SelectionKey对象
		
		//读取interest集合
		int interestSet = key.interestOps();

		boolean isInterestedInAccept  = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
		boolean isInterestedInConnect = (interestSet & SelectionKey.OP_CONNECT) == SelectionKey.OP_CONNECT;
		boolean isInterestedInRead    = (interestSet & SelectionKey.OP_READ) == SelectionKey.OP_READ;
		boolean isInterestedInWrite   = (interestSet & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE;
		
		System.out.println(isInterestedInAccept + ">" + isInterestedInConnect + ">" + isInterestedInRead + ">" + isInterestedInWrite);
		
		//ready 集合是通道已经准备就绪的操作的集合
		int readySet = key.readyOps();
		//判断什么事件就绪
		key.isAcceptable();
		key.isConnectable();
		key.isReadable();
		key.isWritable();
		
		//从SelectionKey访问Channel和Selector
		Channel  channel_0  = key.channel();
		Selector selector_0 = key.selector();

		//可以将一个对象或者更多信息附着到SelectionKey上，这样就能方便的识别某个给定的通道
		Object theObject = null;
		key.attach(theObject);
		Object attachedObj = key.attachment();
		SelectionKey skey = channel.register(selector, SelectionKey.OP_READ, theObject);

	}
}
